#include <gtest/gtest.h>
#include "../mqserver/mq_consumer.hpp"

// Consumer tests for zymq::Consumer, zymq::QueueConsumer, zymq::ConsumerManager

class ConsumerTest : public testing::Test {
    public:
        void SetUp() override {
        }
        void TearDown() override {
        }
};

TEST_F(ConsumerTest, queue_consumer_create_and_choose_round_robin) {    // 轮询选择消费者
    zymq::QueueConsumer qc("queue1");

    // callback placeholder
    zymq::ConsumerCallback cb = [](const std::string &, const zymq::BasicProperties *bp , const std::string &) {};

    auto c1 = qc.create("ctag1", "queue1", true, cb);
    ASSERT_NE(c1, nullptr);
    auto c2 = qc.create("ctag2", "queue1", false, cb);
    ASSERT_NE(c2, nullptr);

    // duplicate tag should fail
    auto dup = qc.create("ctag1", "queue1", true, cb);
    ASSERT_EQ(dup, nullptr);

    // exists checks
    ASSERT_TRUE(qc.exists("ctag1"));
    ASSERT_TRUE(qc.exists("ctag2"));
    ASSERT_FALSE(qc.exists("ctag3"));

    // round-robin choose
    auto pick1 = qc.choose();
    ASSERT_NE(pick1, nullptr);
    ASSERT_EQ(pick1->tag, std::string("ctag1"));

    auto pick2 = qc.choose();
    ASSERT_NE(pick2, nullptr);
    ASSERT_EQ(pick2->tag, std::string("ctag2"));

    auto pick3 = qc.choose();
    ASSERT_NE(pick3, nullptr);
    ASSERT_EQ(pick3->tag, std::string("ctag1"));

    // remove one and verify behavior
    qc.remove("ctag1");
    ASSERT_FALSE(qc.exists("ctag1"));
    ASSERT_TRUE(qc.exists("ctag2"));

    auto pick_after_remove = qc.choose();
    ASSERT_NE(pick_after_remove, nullptr);
    ASSERT_EQ(pick_after_remove->tag, std::string("ctag2"));

    // remove remaining and verify empty
    qc.remove("ctag2");
    ASSERT_TRUE(qc.empty());
    auto pick_null = qc.choose();
    ASSERT_EQ(pick_null, nullptr);
}

TEST_F(ConsumerTest, consumer_manager_lifecycle_and_ops) {
    zymq::ConsumerManager mgr;

    // queue not initialized yet
    ASSERT_TRUE(mgr.empty("queue1"));
    auto none = mgr.choose("queue1");
    ASSERT_EQ(none, nullptr);

    // init queue consumer and create consumers
    mgr.initQueueConsumer("queue1");
    ASSERT_TRUE(mgr.empty("queue1"));

    zymq::ConsumerCallback cb = [](const std::string, const zymq::BasicProperties*, const std::string) {};
    auto c1 = mgr.create("ctag1", "queue1", true, cb);
    ASSERT_NE(c1, nullptr);
    auto c2 = mgr.create("ctag2", "queue1", false, cb);
    ASSERT_NE(c2, nullptr);

    // duplicate should fail
    auto dup = mgr.create("ctag1", "queue1", true, cb);
    ASSERT_EQ(dup, nullptr);

    // exists checks
    ASSERT_TRUE(mgr.exists("ctag1", "queue1"));
    ASSERT_TRUE(mgr.exists("ctag2", "queue1"));
    ASSERT_FALSE(mgr.exists("ctagX", "queue1"));

    // choose round-robin
    auto pick1 = mgr.choose("queue1");
    ASSERT_NE(pick1, nullptr);
    auto pick2 = mgr.choose("queue1");
    ASSERT_NE(pick2, nullptr);
    ASSERT_NE(pick1->tag, pick2->tag);

    // remove and choose again
    mgr.remove("ctag1", "queue1");
    ASSERT_FALSE(mgr.exists("ctag1", "queue1"));
    auto pick_after_remove = mgr.choose("queue1");
    ASSERT_NE(pick_after_remove, nullptr);
    ASSERT_EQ(pick_after_remove->tag, std::string("ctag2"));

    // destroy queue consumer and validate behavior
    mgr.destroyQueueConsumer("queue1");
    ASSERT_TRUE(mgr.empty("queue1"));
    auto pick_null = mgr.choose("queue1");
    ASSERT_EQ(pick_null, nullptr);

    // re-init and clear all
    mgr.initQueueConsumer("queue1");
    auto c3 = mgr.create("ctag3", "queue1", true, cb);
    ASSERT_NE(c3, nullptr);
    mgr.clear();
    ASSERT_TRUE(mgr.empty("queue1"));
    auto pick_after_clear = mgr.choose("queue1");
    ASSERT_EQ(pick_after_clear, nullptr);
}

int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


